use serde::{Deserialize, Serialize};
use std::fs;
use std::path::Path;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Config {
    /// Server bind address
    pub bind: String,
    /// Server port
    pub port: u16,
    /// Maximum number of client connections
    pub max_connections: usize,
    /// Database settings
    pub database: DatabaseConfig,
    /// Persistence settings
    pub persistence: PersistenceConfig,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DatabaseConfig {
    /// Number of databases
    pub databases: usize,
    /// Maximum memory usage in bytes
    pub max_memory: Option<usize>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PersistenceConfig {
    /// Enable RDB snapshots
    pub enable_rdb: bool,
    /// RDB save interval in seconds
    pub rdb_save_interval: u64,
    /// RDB file path
    pub rdb_file: String,
    /// Enable AOF persistence
    pub enable_aof: bool,
    /// AOF file path
    pub aof_file: String,
}

impl Default for Config {
    fn default() -> Self {
        Self {
            bind: "0.0.0.0".to_string(),
            port: 6379,
            max_connections: 1000,
            database: DatabaseConfig {
                databases: 16,
                max_memory: None,
            },
            persistence: PersistenceConfig {
                enable_rdb: true,
                rdb_save_interval: 300, // 5 minutes
                rdb_file: "dump.rdb".to_string(),
                enable_aof: false,
                aof_file: "appendonly.aof".to_string(),
            },
        }
    }
}

impl Config {
    /// Load configuration from file
    pub fn load<P: AsRef<Path>>(path: P) -> Result<Self, Box<dyn std::error::Error>> {
        let content = fs::read_to_string(path)?;
        let config: Config = serde_json::from_str(&content)?;
        Ok(config)
    }

    /// Save configuration to file
    pub fn save<P: AsRef<Path>>(&self, path: P) -> Result<(), Box<dyn std::error::Error>> {
        let content = serde_json::to_string_pretty(self)?;
        fs::write(path, content)?;
        Ok(())
    }
}